# -*- coding: utf-8 -*-
"""
预约相关表单

包含学员预约系统的所有表单验证：
- 创建预约表单
- 修改预约表单
- 取消预约表单
- 时间选择表单
"""

from flask_wtf import FlaskForm
from wtforms import (
    SelectField, DateField, StringField, TextAreaField,
    TimeField, DecimalField, HiddenField, SubmitField
)
from wtforms.validators import DataRequired, Length, Optional, ValidationError, NumberRange
from datetime import datetime, date, time, timedelta

from app.models.user import User
from app.models.table import Table
from app.models.reservation import Reservation
from app.controllers.reservation_controller import ReservationController


class CreateReservationForm(FlaskForm):
    """创建预约表单"""

    coach_id = SelectField(
        '选择教练',
        choices=[],
        validators=[DataRequired(message='请选择教练')],
        render_kw={'class': 'form-select', 'style': 'display: none;'}
    )

    table_id = SelectField(
        '选择球台',
        choices=[],
        validators=[DataRequired(message='请选择球台')],
        render_kw={'class': 'form-select', 'style': 'display: none;'}
    )

    reservation_date = DateField(
        '预约日期',
        validators=[DataRequired(message='请选择预约日期')],
        render_kw={'class': 'form-control', 'min': date.today().isoformat()}
    )

    start_time = TimeField(
        '开始时间',
        validators=[DataRequired(message='请选择开始时间')],
        render_kw={'class': 'form-control'}
    )

    end_time = TimeField(
        '结束时间',
        validators=[DataRequired(message='请选择结束时间')],
        render_kw={'class': 'form-control'}
    )

    notes = TextAreaField(
        '备注信息',
        validators=[Optional(), Length(max=200, message='备注信息不能超过200字')],
        render_kw={'class': 'form-control', 'rows': 3, 'placeholder': '可填写特殊要求或说明...'}
    )

    submit = SubmitField('确认预约', render_kw={'class': 'btn btn-primary'})

    def __init__(self, student_id=None, campus_id=None, *args, **kwargs):
        super(CreateReservationForm, self).__init__(*args, **kwargs)
        self.student_id = student_id
        self.campus_id = campus_id

        # 动态加载教练选项
        if student_id:
            self._load_coach_choices()

        # 动态加载球台选项
        if campus_id:
            self._load_table_choices()

    def _load_coach_choices(self):
        """加载可选教练"""
        try:
            result = ReservationController.get_available_coaches(self.student_id, self.campus_id)
            if result['success']:
                coaches = result['data']['coaches']
                self.coach_id.choices = [('', '请选择教练')] + [
                    (str(coach.id), f"{coach.real_name} - {coach.coach_level or '教练'}")
                    for coach in coaches
                ]
            else:
                self.coach_id.choices = [('', '暂无可选教练')]
        except Exception:
            self.coach_id.choices = [('', '加载教练失败')]

    def _load_table_choices(self):
        """加载球台选项"""
        try:
            # 添加调试信息
            print(f"DEBUG: 加载球台选项 - campus_id: {self.campus_id}")

            if not self.campus_id:
                print("DEBUG: campus_id 为空，无法加载球台")
                self.table_id.choices = [('', '未指定校区')]
                return

            tables = Table.query.filter(
                Table.campus_id == self.campus_id,
                Table.status == 'available'
            ).all()

            print(f"DEBUG: 查询到球台数量: {len(tables)}")
            for table in tables:
                print(f"DEBUG: 球台 - ID: {table.id}, 名称: {table.name}, 校区: {table.campus_id}")

            self.table_id.choices = [('', '请先选择时间')] + [
                (str(table.id), f"{table.name} - 标准球台")
                for table in tables
            ]

            print(f"DEBUG: 设置choices: {self.table_id.choices}")

        except Exception as e:
            print(f"DEBUG: 加载球台失败 - 错误: {str(e)}")
            import traceback
            traceback.print_exc()
            self.table_id.choices = [('', '加载球台失败')]

    def validate_reservation_date(self, field):
        """验证预约日期"""
        if field.data < date.today():
            raise ValidationError('不能预约过去的日期')

        max_date = date.today() + timedelta(days=30)
        if field.data > max_date:
            raise ValidationError('最多只能提前30天预约')

    def validate_start_time(self, field):
        """验证开始时间"""
        if not field.data:
            return

        # 检查营业时间（8:00-22:00）
        if field.data < time(8, 0) or field.data > time(22, 0):
            raise ValidationError('预约时间必须在8:00-22:00之间')

        # 检查是否提前足够时间
        if self.reservation_date.data:
            reservation_datetime = datetime.combine(self.reservation_date.data, field.data)
            min_advance_time = datetime.now() + timedelta(hours=2)
            if reservation_datetime < min_advance_time:
                raise ValidationError('至少需要提前2小时预约')

    def validate_end_time(self, field):
        """验证结束时间"""
        if not field.data or not self.start_time.data:
            return

        # 检查结束时间晚于开始时间
        if field.data <= self.start_time.data:
            raise ValidationError('结束时间必须晚于开始时间')

        # 检查时长限制
        start_dt = datetime.combine(date.today(), self.start_time.data)
        end_dt = datetime.combine(date.today(), field.data)
        duration_minutes = (end_dt - start_dt).seconds / 60

        if duration_minutes < 30:
            raise ValidationError('预约时长不能少于30分钟')
        if duration_minutes > 240:
            raise ValidationError('预约时长不能超过4小时')

        # 检查营业时间
        if field.data > time(22, 0):
            raise ValidationError('结束时间不能晚于22:00')

    def validate_coach_id(self, field):
        """验证教练选择"""
        print(f"DEBUG: 验证教练ID - field.data: {field.data}")
        if not field.data:
            print("DEBUG: 教练ID为空，验证失败")
            raise ValidationError('请选择教练')

        try:
            coach_id = int(field.data)
            print(f"DEBUG: 教练ID转换成功: {coach_id}")
            if self.student_id:
                result = ReservationController._check_student_coach_relation(
                    self.student_id, coach_id
                )
                print(f"DEBUG: 教练关系检查结果: {result}")
                if not result['success']:
                    print(f"DEBUG: 教练关系检查失败: {result['message']}")
                    raise ValidationError(result['message'])
        except ValueError:
            print("DEBUG: 教练ID格式无效")
            raise ValidationError('请选择有效的教练')

    def validate_table_id(self, field):
        """验证球台和时间冲突"""
        print(f"DEBUG: 验证球台ID - field.data: {field.data}")
        if not field.data:
            print("DEBUG: 球台ID为空，验证失败")
            raise ValidationError('请选择球台')

        if not all([self.reservation_date.data,
                   self.start_time.data, self.end_time.data]):
            print("DEBUG: 时间字段不完整，跳过时间冲突检查")
            return

        try:
            table_id = int(field.data)
            print(f"DEBUG: 球台ID转换成功: {table_id}, 检查时间冲突...")
            has_conflict = Reservation.check_time_conflict(
                table_id, self.reservation_date.data,
                self.start_time.data, self.end_time.data
            )
            print(f"DEBUG: 时间冲突检查结果: {has_conflict}")
            if has_conflict:
                print("DEBUG: 发现时间冲突")
                raise ValidationError('该时间段球台已被预约，请选择其他时间或球台')
        except ValueError:
            print("DEBUG: 球台ID格式无效")
            raise ValidationError('请选择有效的球台')


class EditReservationForm(FlaskForm):
    """修改预约表单"""

    table_id = SelectField(
        '选择球台',
        choices=[],
        validators=[DataRequired(message='请选择球台')],
        render_kw={'class': 'form-select'}
    )

    reservation_date = DateField(
        '预约日期',
        validators=[DataRequired(message='请选择预约日期')],
        render_kw={'class': 'form-control', 'min': date.today().isoformat()}
    )

    start_time = TimeField(
        '开始时间',
        validators=[DataRequired(message='请选择开始时间')],
        render_kw={'class': 'form-control'}
    )

    end_time = TimeField(
        '结束时间',
        validators=[DataRequired(message='请选择结束时间')],
        render_kw={'class': 'form-control'}
    )

    submit = SubmitField('确认修改', render_kw={'class': 'btn btn-primary'})

    def __init__(self, reservation=None, campus_id=None, *args, **kwargs):
        super(EditReservationForm, self).__init__(*args, **kwargs)
        self.reservation = reservation
        self.campus_id = campus_id

        # 加载球台选项
        if campus_id:
            self._load_table_choices()

        # 设置初始值
        if reservation:
            self.reservation_date.data = reservation.reservation_date
            self.start_time.data = reservation.start_time
            self.end_time.data = reservation.end_time
            self.table_id.data = str(reservation.table_id)

    def _load_table_choices(self):
        """加载球台选项"""
        try:
            tables = Table.query.filter(
                Table.campus_id == self.campus_id,
                Table.status == 'available'
            ).all()

            self.table_id.choices = [
                (str(table.id), f"{table.name} - 标准球台")
                for table in tables
            ]
        except Exception:
            self.table_id.choices = [('', '加载球台失败')]

    def validate_reservation_date(self, field):
        """验证预约日期"""
        if field.data < date.today():
            raise ValidationError('不能预约过去的日期')

        max_date = date.today() + timedelta(days=30)
        if field.data > max_date:
            raise ValidationError('最多只能提前30天预约')

    def validate_start_time(self, field):
        """验证开始时间"""
        if not field.data:
            return

        # 检查营业时间
        if field.data < time(8, 0) or field.data > time(22, 0):
            raise ValidationError('预约时间必须在8:00-22:00之间')

        # 检查是否提前足够时间
        if self.reservation_date.data:
            reservation_datetime = datetime.combine(self.reservation_date.data, field.data)
            min_advance_time = datetime.now() + timedelta(hours=2)
            if reservation_datetime < min_advance_time:
                raise ValidationError('至少需要提前2小时预约')

    def validate_end_time(self, field):
        """验证结束时间"""
        if not field.data or not self.start_time.data:
            return

        if field.data <= self.start_time.data:
            raise ValidationError('结束时间必须晚于开始时间')

        # 检查时长限制
        start_dt = datetime.combine(date.today(), self.start_time.data)
        end_dt = datetime.combine(date.today(), field.data)
        duration_minutes = (end_dt - start_dt).seconds / 60

        if duration_minutes < 30:
            raise ValidationError('预约时长不能少于30分钟')
        if duration_minutes > 240:
            raise ValidationError('预约时长不能超过4小时')

        if field.data > time(22, 0):
            raise ValidationError('结束时间不能晚于22:00')

    def validate_table_id(self, field):
        """验证球台冲突"""
        if not all([field.data, self.reservation_date.data,
                   self.start_time.data, self.end_time.data]):
            return

        try:
            table_id = int(field.data)
            exclude_id = self.reservation.id if self.reservation else None

            has_conflict = Reservation.check_time_conflict(
                table_id, self.reservation_date.data,
                self.start_time.data, self.end_time.data,
                exclude_id=exclude_id
            )
            if has_conflict:
                raise ValidationError('该时间段球台已被预约，请选择其他时间或球台')
        except ValueError:
            raise ValidationError('请选择有效的球台')


class CancelReservationForm(FlaskForm):
    """取消预约表单"""

    cancel_reason = SelectField(
        '取消原因',
        choices=[
            ('', '请选择取消原因'),
            ('schedule_conflict', '时间冲突'),
            ('personal_reason', '个人原因'),
            ('weather', '天气原因'),
            ('health', '身体不适'),
            ('emergency', '紧急情况'),
            ('other', '其他原因')
        ],
        validators=[DataRequired(message='请选择取消原因')],
        render_kw={'class': 'form-select'}
    )

    additional_notes = TextAreaField(
        '补充说明',
        validators=[Optional(), Length(max=200, message='补充说明不能超过200字')],
        render_kw={
            'class': 'form-control',
            'rows': 3,
            'placeholder': '可填写详细的取消原因...'
        }
    )

    submit = SubmitField('确认取消', render_kw={'class': 'btn btn-danger'})

    def get_reason_display(self):
        """获取取消原因显示文本"""
        reason_map = {
            'schedule_conflict': '时间冲突',
            'personal_reason': '个人原因',
            'weather': '天气原因',
            'health': '身体不适',
            'emergency': '紧急情况',
            'other': '其他原因'
        }
        return reason_map.get(self.cancel_reason.data, self.cancel_reason.data)


class TimeSlotForm(FlaskForm):
    """时间段选择表单"""

    date = DateField(
        '选择日期',
        validators=[DataRequired(message='请选择日期')],
        render_kw={'class': 'form-control', 'min': date.today().isoformat()}
    )

    coach_id = HiddenField('教练ID')
    table_id = HiddenField('球台ID')

    def validate_date(self, field):
        """验证日期"""
        if field.data < date.today():
            raise ValidationError('不能选择过去的日期')

        max_date = date.today() + timedelta(days=30)
        if field.data > max_date:
            raise ValidationError('最多只能提前30天预约')


class ReservationFilterForm(FlaskForm):
    """预约筛选表单"""

    status = SelectField(
        '状态',
        choices=[
            ('', '全部状态'),
            ('pending', '待确认'),
            ('confirmed', '已确认'),
            ('cancelled', '已取消'),
            ('completed', '已完成'),
            ('no_show', '未出席')
        ],
        validators=[Optional()],
        render_kw={'class': 'form-select'}
    )

    start_date = DateField(
        '开始日期',
        validators=[Optional()],
        render_kw={'class': 'form-control'}
    )

    end_date = DateField(
        '结束日期',
        validators=[Optional()],
        render_kw={'class': 'form-control'}
    )

    coach_id = SelectField(
        '教练',
        choices=[],
        validators=[Optional()],
        render_kw={'class': 'form-select'}
    )

    submit = SubmitField('筛选', render_kw={'class': 'btn btn-primary'})

    def __init__(self, student_id=None, *args, **kwargs):
        super(ReservationFilterForm, self).__init__(*args, **kwargs)

        # 加载教练选项
        if student_id:
            self._load_coach_choices(student_id)

    def _load_coach_choices(self, student_id):
        """加载教练选项"""
        try:
            result = ReservationController.get_available_coaches(student_id)
            if result['success']:
                coaches = result['data']['coaches']
                self.coach_id.choices = [('', '全部教练')] + [
                    (str(coach.id), coach.real_name)
                    for coach in coaches
                ]
            else:
                self.coach_id.choices = [('', '全部教练')]
        except Exception:
            self.coach_id.choices = [('', '全部教练')]

    def validate_end_date(self, field):
        """验证结束日期"""
        if field.data and self.start_date.data:
            if field.data < self.start_date.data:
                raise ValidationError('结束日期不能早于开始日期')


class AdminEditReservationForm(FlaskForm):
    """管理员编辑预约表单"""

    coach_id = SelectField(
        '教练',
        choices=[],
        validators=[DataRequired(message='请选择教练')],
        render_kw={'class': 'form-select'}
    )

    table_id = SelectField(
        '球台',
        choices=[],
        validators=[DataRequired(message='请选择球台')],
        render_kw={'class': 'form-select'}
    )

    reservation_date = DateField(
        '预约日期',
        validators=[DataRequired(message='请选择预约日期')],
        render_kw={'class': 'form-control'}
    )

    start_time = TimeField(
        '开始时间',
        validators=[DataRequired(message='请选择开始时间')],
        render_kw={'class': 'form-control'}
    )

    end_time = TimeField(
        '结束时间',
        validators=[DataRequired(message='请选择结束时间')],
        render_kw={'class': 'form-control'}
    )

    price = DecimalField(
        '课程费用',
        validators=[Optional(), NumberRange(min=0, max=999.99, message='费用必须在0-999.99之间')],
        render_kw={'class': 'form-control', 'step': '0.01', 'placeholder': '请输入课程费用'}
    )

    status = SelectField(
        '预约状态',
        choices=[
            ('pending', '待确认'),
            ('confirmed', '已确认'),
            ('cancelled', '已取消'),
            ('completed', '已完成'),
            ('no_show', '未出席')
        ],
        validators=[DataRequired(message='请选择预约状态')],
        render_kw={'class': 'form-select'}
    )

    notes = TextAreaField(
        '预约备注',
        validators=[Optional(), Length(max=500, message='备注信息不能超过500字')],
        render_kw={'class': 'form-control', 'rows': 3, 'placeholder': '可填写预约相关的备注信息...'}
    )

    submit = SubmitField('保存修改', render_kw={'class': 'btn btn-primary'})

    def __init__(self, reservation=None, campus_id=None, *args, **kwargs):
        super(AdminEditReservationForm, self).__init__(*args, **kwargs)
        self.reservation = reservation
        self.campus_id = campus_id

        # 加载选项
        if campus_id:
            self._load_coach_choices()
            self._load_table_choices()

        # 设置初始值
        if reservation:
            self.coach_id.data = str(reservation.coach_id)
            self.table_id.data = str(reservation.table_id)
            self.reservation_date.data = reservation.reservation_date
            self.start_time.data = reservation.start_time
            self.end_time.data = reservation.end_time
            self.price.data = reservation.price
            self.status.data = reservation.status
            # notes字段在数据库中不存在，保持为空

    def _load_coach_choices(self):
        """加载教练选项"""
        try:
            coaches = User.query.filter(
                User.role == 'coach',
                User.campus_id == self.campus_id,
                User.status == 'active'
            ).all()

            self.coach_id.choices = [
                (str(coach.id), f"{coach.real_name} - {coach.coach_level or '教练'}")
                for coach in coaches
            ]
        except Exception:
            self.coach_id.choices = [('', '加载教练失败')]

    def _load_table_choices(self):
        """加载球台选项"""
        try:
            tables = Table.query.filter(
                Table.campus_id == self.campus_id,
                Table.status.in_(['available', 'maintenance'])  # 管理员可以选择维护中的球台
            ).all()

            self.table_id.choices = [
                (str(table.id), f"{table.name} - {table.get_status_display()}")
                for table in tables
            ]
        except Exception:
            self.table_id.choices = [('', '加载球台失败')]

    def validate_reservation_date(self, field):
        """验证预约日期"""
        if field.data < date.today() - timedelta(days=7):
            raise ValidationError('不能编辑一周前的预约')

        max_date = date.today() + timedelta(days=90)  # 管理员可以预约更远的日期
        if field.data > max_date:
            raise ValidationError('最多只能提前90天预约')

    def validate_start_time(self, field):
        """验证开始时间"""
        if not field.data:
            return

        # 管理员可以不受营业时间限制，但需要合理范围
        if field.data < time(6, 0) or field.data > time(23, 59):
            raise ValidationError('开始时间必须在6:00-23:59之间')

    def validate_end_time(self, field):
        """验证结束时间"""
        if not field.data or not self.start_time.data:
            return

        if field.data <= self.start_time.data:
            raise ValidationError('结束时间必须晚于开始时间')

        # 检查时长限制
        start_dt = datetime.combine(date.today(), self.start_time.data)
        end_dt = datetime.combine(date.today(), field.data)
        duration_minutes = (end_dt - start_dt).seconds / 60

        if duration_minutes < 15:  # 管理员可以设置更短的时间
            raise ValidationError('预约时长不能少于15分钟')
        if duration_minutes > 480:  # 8小时
            raise ValidationError('预约时长不能超过8小时')

    def validate_table_id(self, field):
        """验证球台冲突（管理员可以忽略冲突）"""
        if not all([field.data, self.reservation_date.data,
                   self.start_time.data, self.end_time.data]):
            return

        # 管理员编辑时可以选择忽略冲突，这里只做基本验证
        try:
            table_id = int(field.data)
            table = Table.query.get(table_id)
            if not table:
                raise ValidationError('选择的球台不存在')
            if table.campus_id != self.campus_id:
                raise ValidationError('不能选择其他校区的球台')
        except ValueError:
            raise ValidationError('请选择有效的球台')

    def calculate_duration_minutes(self):
        """计算预约时长（分钟）"""
        if self.start_time.data and self.end_time.data:
            start_dt = datetime.combine(date.today(), self.start_time.data)
            end_dt = datetime.combine(date.today(), self.end_time.data)
            return int((end_dt - start_dt).seconds / 60)
        return 0